﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="MenuScreen.cs" company="">
//   
// </copyright>
// <summary>
//   The menu screen.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

/*
 * Author: Juan Mompean Esteban
 * Created: 26-11-2011
 */
namespace ITU_vs_Zombies.Menu.Screens
{
    using System.Collections.Generic;

    using Microsoft.Xna.Framework;
    using Microsoft.Xna.Framework.Graphics;
    using Microsoft.Xna.Framework.Input;

    /// <summary>
    /// The menu screen.
    /// </summary>
    public abstract class MenuScreen : GameScreen
    {
        #region Constants and Fields

        /// <summary>
        /// The menu cancel.
        /// </summary>
        private readonly InputAction menuCancel;

        /// <summary>
        /// The menu down.
        /// </summary>
        private readonly InputAction menuDown;

        /// <summary>
        /// The menu entries.
        /// </summary>
        private readonly List<MenuEntry> menuEntries = new List<MenuEntry>();

        /// <summary>
        /// The menu select.
        /// </summary>
        private readonly InputAction menuSelect;

        /// <summary>
        /// The menu title.
        /// </summary>
        private readonly string menuTitle;

        /// <summary>
        /// The menu up.
        /// </summary>
        private readonly InputAction menuUp;

        /// <summary>
        /// The selected entry.
        /// </summary>
        private int selectedEntry;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="MenuScreen"/> class.
        /// </summary>
        /// <param name="menuTitle">
        /// The menu title.
        /// </param>
        public MenuScreen(string menuTitle)
        {
            this.menuTitle = menuTitle;

            this.menuUp = new InputAction(new[] { Keys.Up }, true);
            this.menuDown = new InputAction(new[] { Keys.Down }, true);
            this.menuSelect = new InputAction(new[] { Keys.Enter, Keys.Space }, true);
            this.menuCancel = new InputAction(new[] { Keys.Escape }, true);
        }

        #endregion

        #region Properties

        /// <summary>
        /// Gets MenuEntries.
        /// </summary>
        protected IList<MenuEntry> MenuEntries
        {
            get
            {
                return this.menuEntries;
            }
        }

        #endregion

        #region Public Methods

        /// <summary>
        /// The draw.
        /// </summary>
        /// <param name="gameTime">
        /// The game time.
        /// </param>
        public override void Draw(GameTime gameTime)
        {
            this.UpdateMenuEntryLocations();

            GraphicsDevice graphics = this.ScreenManager.GraphicsDevice;
            SpriteBatch spriteBatch = this.ScreenManager.SpriteBatch;
            SpriteFont font = this.ScreenManager.Font;

            spriteBatch.Begin();

            for (int i = 0; i < this.menuEntries.Count; i++)
            {
                MenuEntry menuEntry = this.menuEntries[i];

                bool isSelected = this.IsActive && (i == this.selectedEntry);

                menuEntry.Draw(this, isSelected, gameTime);
            }

            var titlePosition = new Vector2(graphics.Viewport.Width / 2, 80);
            Vector2 titleOrigin = font.MeasureString(this.menuTitle) / 2;
            var titleColor = new Color(192, 192, 192);
            float titleScale = 1.25f;

            spriteBatch.DrawString(
                font, this.menuTitle, titlePosition, titleColor, 0, titleOrigin, titleScale, SpriteEffects.None, 0);

            spriteBatch.End();
        }

        /// <summary>
        /// The handle input.
        /// </summary>
        /// <param name="gameTime">
        /// The game time.
        /// </param>
        /// <param name="input">
        /// The input.
        /// </param>
        public override void HandleInput(GameTime gameTime, InputState input)
        {
            if (this.menuUp.Evaluate(input))
            {
                this.selectedEntry--;

                if (this.selectedEntry < 0)
                {
                    this.selectedEntry = this.menuEntries.Count - 1;
                }
            }

            if (this.menuDown.Evaluate(input))
            {
                this.selectedEntry++;

                if (this.selectedEntry >= this.menuEntries.Count)
                {
                    this.selectedEntry = 0;
                }
            }

            if (this.menuSelect.Evaluate(input))
            {
                this.OnSelectEntry(this.selectedEntry);
            }
            else if (this.menuCancel.Evaluate(input))
            {
                this.OnCancel();
            }
        }

        /// <summary>
        /// The update.
        /// </summary>
        /// <param name="gameTime">
        /// The game time.
        /// </param>
        /// <param name="otherScreenHasFocus">
        /// The other screen has focus.
        /// </param>
        /// <param name="coveredByOtherScreen">
        /// The covered by other screen.
        /// </param>
        public override void Update(GameTime gameTime, bool otherScreenHasFocus, bool coveredByOtherScreen)
        {
            base.Update(gameTime, otherScreenHasFocus, coveredByOtherScreen);

            for (int i = 0; i < this.menuEntries.Count; i++)
            {
                bool isSelected = this.IsActive && (i == this.selectedEntry);

                this.menuEntries[i].Update(this, isSelected, gameTime);
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// The on cancel.
        /// </summary>
        protected virtual void OnCancel()
        {
            this.ExitScreen();
        }

        /// <summary>
        /// The on cancel.
        /// </summary>
        /// <param name="sender">
        /// The sender.
        /// </param>
        /// <param name="o">
        /// The o.
        /// </param>
        protected virtual void OnCancel(object sender, object o)
        {
            this.OnCancel();
        }

        /// <summary>
        /// The on select entry.
        /// </summary>
        /// <param name="entryIndex">
        /// The entry index.
        /// </param>
        protected virtual void OnSelectEntry(int entryIndex)
        {
            this.menuEntries[entryIndex].OnSelectEntry();
        }

        /// <summary>
        /// The update menu entry locations.
        /// </summary>
        protected virtual void UpdateMenuEntryLocations()
        {
            var position = new Vector2(0f, 175f);

            foreach (MenuEntry menuEntry in this.menuEntries)
            {
                position.X = (this.ScreenManager.GraphicsDevice.Viewport.Width / 2) - (menuEntry.GetWidth(this) / 2);

                menuEntry.Position = position;

                position.Y += menuEntry.GetHeight(this);
            }
        }

        #endregion
    }
}